#include<stdarg.h>
#include "uart0.h"

/*uart Special Registers off_size*/

#define _putchar(x) do{if(x=='\n') uart0_putchar('\r');uart0_putchar((char)(x));}while(0)

#define CPLD_LED		*((volatile unsigned char *)0x20800000)

#define UART0_BASE		(0x50000000)
#define UART1_BASE		(0x50004000)

#define ULCON			0x00
#define UCON			0x04
#define UFCON			0x08
#define UMCON			0x0c
#define UTRSTAT			0x10
#define UERSTAT			0x14
#define UFSTAT			0x18
#define UMSTAT			0x1c
#define UTXH			0x20
#define URXH			0x24
#define UBRDIV			0x28

/* UART Status Register bits */
#define UTRSTAT_T_EMPTY		(1 << 2)
#define UTRSTAT_BUF_EMPTY	(1 << 1)
#define UTRSTAT_R_READY		(1 << 0)

#define ULCON0			*((volatile unsigned int *)(UART0_BASE+ULCON))
#define UCON0			*((volatile unsigned int *)(UART0_BASE+UCON))
#define UFCON0			*((volatile unsigned int *)(UART0_BASE+UFCON))
#define UMCON0			*((volatile unsigned int *)(UART0_BASE+UMCON))
#define UBRDIV0			*((volatile unsigned int *)(UART0_BASE+UBRDIV))
#define UTRSTAT0		*((volatile unsigned int *)(UART0_BASE+UTRSTAT))
#define UTXH0			*((volatile unsigned int *)(UART0_BASE+UTXH))
#define URXH0			*((volatile unsigned int *)(UART0_BASE+URXH))

#define GPHCON			*((volatile unsigned int *)(0X56000070))
#define GPHDAT			*((volatile unsigned int *)(0X56000074))

int uart0_init(void)
{
	GPHCON = 0x00faaa;
	GPHDAT = 0x7ff;
	/* 8 N 1 */
	ULCON0=3;
	/* interrupt request or polling mode */
	UCON0 = 5;
	/* init UFCON0 UMCON0 */
	UFCON0 = 0;
	UMCON0 = 0;
	/*
	* UBRDIV = PCLK/(baudrate * 16) - 1
	* PCLK = 50.7Mhz
	*
	* baudrate 115200 
	*/
	UBRDIV0 = 27;

	return 0;
}

char uart0_getchar(void)
{
	char ch;
	
	while (!(UTRSTAT0 & UTRSTAT_R_READY))
		;
	ch = URXH0;
	
	return ch;
}

int uart0_putchar(char ch)
{
	while (!(UTRSTAT0 & UTRSTAT_T_EMPTY))
		;
		
	UTXH0= ch;
	
	return 0;
}

int led_init(void)
{
	CPLD_LED = 0x0;
	return 0;
}

int led_on(int num)
{
	CPLD_LED |= 1<<num;
	
	return 0;
}

int led_off()
{
	CPLD_LED = 0;
	
	return 0;
}

void output_int(unsigned int num, const int base)
{
		const char *digit = "0123456789ABCDEF";
		unsigned int buf[32];
		int i = 0;
		char ch;
		
		if(base == 10)
			{
				do{
					buf[i]= num%10;
					num = num / 10;
					i++;
				}while (num > 0);	
			}	
		if(base == 16)
			{
				do
				{
					buf[i] = num%16;
					num = num / 16;
					i++;	
				}while(num > 0);
			}
			while(--i >= 0)
			{
				ch = digit[buf[i]];
				_putchar(ch);
			}
}
int my_printf(const char *format,...){
		va_list unnamed_p;
		char *p, *sval;
		unsigned int value_i;
		va_start(unnamed_p, format);
		
		for(p=(char*)format; *p!='\0'; p++)
		{
			if(*p!='%')
				{
					_putchar(*p);
					continue;	
				}
			switch(*++p)
			{
				case'd':
					value_i = va_arg(unnamed_p,unsigned int);
					output_int(value_i, 10);
					break;
				case's':
					for(sval = va_arg(unnamed_p, char*); *sval; sval++)
						_putchar(*sval);
				case'x':
					value_i = va_arg(unnamed_p, unsigned int);
					output_int(value_i,16);
					break;
				default:
					_putchar(*p);
					break;
			}
		}
		va_end(unnamed_p);
		return 0;
}

int uart0_test(void)
{
	char ch;
	int num;

	uart0_init();
	
	led_init();
	
	my_printf("Hello,AKA!\n");
	
	while(1)
	{
		my_printf("please input a num from 0 to 7\n");
		ch = uart0_getchar();
		led_off();
		
		num = ch-'0';
		uart0_putchar(ch);
		my_printf("\n");
		led_on(num);
		
	}
	
	return 0;
}

